home *** CD-ROM | disk | FTP | other *** search
/ CD Ware Multimedia 1995 May / cd Ware (Juegos) Epimundo.iso / DOS / C / MSECDL.ZIP / MSECDLY.C < prev   
Encoding:
C/C++ Source or Header  |  1993-10-28  |  4.9 KB  |  197 lines

  1. /* pause.c
  2. // Contributed by Bill Gatliff, Owensboro KY
  3. // CompuServe ID: 72630,3653 voice 502-684-5352 (as of 12 Oct '93)
  4. //
  5. //    Routines associated with a fairly-precise delay timer that is
  6. // "interrupt friendly."
  7. //
  8. // The timer doesn't take into account function-call overhead,
  9. // so the delay will always run slightly long.
  10. //
  11. // According to the IBM PC/XT Technical reference, Timer 0 is run
  12. // in Mode 3, and is initialized with a reload value of 0xffff,
  13. // which will cause the 8253 to generate interrupts with a
  14. // periodicity of 53msec.
  15. // I adjust that reload value to 0xffffU/53, which will generate
  16. // interrupts every 1 msec. I then call the BIOS Timer 0 ISR
  17. // every 53 interrupts to update the system clock, floppy drive, etc.
  18. //
  19. // This module contains the following procedures:
  20. //
  21. // void interrupt msecDelayISR( void );
  22. // void interrupt (*oldISR )( void );
  23. // int initDelay( void );
  24. // void deinitDelay( void );
  25. // void msecDelay( unsigned int msecs );
  26. // unsigned int getTimerCount( void );
  27. //
  28. // initDelay() sets up the ISR, etc. It's called automatically
  29. // the first time msecDelay() is called.
  30. //
  31. // deinitDelay() is called automatically at program exit,
  32. // but may be called beforehand without damage.
  33. //
  34. // msecDelay( unsigned int msecs ) suspends foreground execution
  35. // for _msecs_ milliseconds.
  36. //
  37. // getTimerCount() returns the current internal TimerCount value.
  38. //
  39. // msecDelayISR() is the interrupt-service-routine that overtakes
  40. // the standard BIOS timer hardware interrupt without corrupting
  41. // the system clock. System time should not be significantly
  42. // effected by the use of these routines.
  43. //
  44. // Programmer    Date        Modification
  45. // ---------------------------------------------------------------------
  46. //        bg        11 Oct 93    Created Original
  47. //        bg        12 Oct 93    Added msecTimeout,msecExpired
  48. */
  49. #include <conio.h>
  50. #include <dos.h>
  51. #include <stdio.h>
  52. #include <stdlib.h>
  53.  
  54. #define BIOSTimerAddr        ((long far*)0x40006cL)
  55. #define TimerIRQ            0x08        /* Timer 0 IRQ number */
  56. #define TimerCtrlPort        0x43        /* Control port for Timer 0 */
  57. #define TimerReloadPort    0x40        /* Register port for Timer 0 */
  58. #define TimerReloadVal        0x0FFFFU/53    /* Reload value for 1msec delay */
  59.  
  60. void interrupt msecDelayISR( void );
  61. void interrupt (*oldISR )( void );
  62. int initDelay( void );
  63. void deinitDelay( void );
  64. void msecDelay( unsigned int msecs );
  65. int msecExpired( unsigned long timeOutTime );
  66.  
  67. static volatile unsigned int IRQCounter =0;
  68. static volatile unsigned int TimerCount =0;
  69. static char delayInit =0;
  70.  
  71. /*
  72. // This procedure hangs out for _msecs_ milliseconds.
  73. // There's no need to disable interrupts while adjusting TimerCount,
  74. // since even the XT (I think) can handle 16 bits in a single instruction
  75. // cycle, which by definition isn't interruptable.
  76. */
  77. void msecDelay( unsigned int msecs )
  78. {
  79.     if( !delayInit )
  80.         if( !initDelay() )
  81.             return;
  82.  
  83.     TimerCount =0;
  84.     while( TimerCount < msecs );
  85. }
  86.  
  87. /*
  88. // This procedure returns the TimerCount value.
  89. //
  90. */
  91. unsigned int getTimerCount( void )
  92. {
  93.     return TimerCount;
  94. }
  95.  
  96. /*
  97. // initDelay -- initializes the delay timer.
  98. // Returns 1 on success, 0 if initialization fails.
  99. // Initialization will fail if atexit() fails.
  100. */
  101. int initDelay( void )
  102. {
  103.     int retVal;
  104.  
  105.     /* don't initialize again! */
  106.     if( delayInit )
  107.         return 1;
  108.  
  109.     delayInit =1;
  110.     oldISR =getvect( TimerIRQ );
  111.     setvect( TimerIRQ,msecDelayISR );
  112.     if( atexit( deinitDelay ) != 0 )
  113.         {
  114.         deinitDelay();
  115.         retVal =0;
  116.         }
  117.     else
  118.         {
  119.         /* reload the timer for 1 msec delay */
  120.         _disable();
  121.         outportb( TimerCtrlPort,0x36 );
  122.         outportb( TimerReloadPort,TimerReloadVal );
  123.         outportb( TimerReloadPort,TimerReloadVal >> 8 );
  124.         _enable();
  125.         retVal =1;
  126.         }
  127.     return retVal;
  128. }
  129.  
  130.  
  131. /*
  132. // Timer 0 Interrupt Service routine.
  133. // Merely updates TimerCount (every msec), and executes the
  134. // system clock every 53 msec (approx).
  135. // Compile WITHOUT stack-overflow checking.
  136. */
  137. #pragma -N-
  138. void interrupt msecDelayISR( void )
  139. {
  140.     /* clear the interrupt request */
  141.     asm    mov al,20h
  142.     asm out 20h,al
  143.  
  144.     /* update our 1msec timer */
  145.     TimerCount++;
  146.  
  147.     /* need to update system clock? */
  148.     if( ++IRQCounter >=52 )
  149.         {
  150.         IRQCounter =0;
  151.         _chain_intr( oldISR );
  152.         }
  153. }
  154. #pragma -N.
  155.  
  156. /*
  157. // Procedure to restore Timer 0 to it's default state.
  158. */
  159. void deinitDelay( void )
  160. {
  161.     if( !delayInit )
  162.         return;
  163.  
  164.     /* don't deinit twice! */
  165.     delayInit =0;
  166.  
  167.     /* restore old ISR */
  168.     _disable();
  169.     setvect( TimerIRQ,oldISR );
  170.  
  171.     /* reset timer for 53msec delay */
  172.     outportb( TimerCtrlPort,0x36 );
  173.     outportb( TimerReloadPort,0 );
  174.     outportb( TimerReloadPort,0 );
  175.     _enable();
  176. }
  177.  
  178. #ifdef KILL
  179. /*
  180. // Test procedure.
  181. */
  182. #include <time.h>
  183. int main( void )
  184. {
  185.     clock_t curTime,startTime;
  186.  
  187.     msecDelay( 0 );
  188.  
  189.     startTime =clock() /CLK_TCK;
  190.     fprintf( stdout,"\nPausing for 10 seconds...\n" );
  191.     while(( curTime =clock() / CLK_TCK ) < startTime + 10 )
  192.         fprintf( stdout,"%d\r",TimerCount );
  193.  
  194.     return 1;
  195. }
  196. #endif
  197.